package com.pylc.model.dao.impl;

import com.pylc.common.bean.Pager;
import com.pylc.model.dao.BaseDao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * @author Lindsey
 */
@Repository
public class BaseDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {

    private Class<T> entityClass;
    protected SessionFactory sessionFactory;
    protected HibernateTemplate hibernateTemplate = null;

    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        this.entityClass = null;
        Class c = getClass();
        Type type = c.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
            this.entityClass = (Class<T>) parameterizedType[0];
        }
    }

    @Resource
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public HibernateTemplate getHibernateTemplate() {
        if (hibernateTemplate == null) {
            hibernateTemplate = new HibernateTemplate(sessionFactory);
        }
        return hibernateTemplate;
    }

    protected Session getSession() {
        return getHibernateTemplate().getSessionFactory().getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    public T get(PK id) {
        Assert.notNull(id, "id is required");
        return (T) getHibernateTemplate().get(entityClass, id);
    }

    @SuppressWarnings("unchecked")
    public T load(PK id) {
        Assert.notNull(id, "id is required");
        return (T) getHibernateTemplate().load(entityClass, id);
    }

    @SuppressWarnings("unchecked")
    public List<T> get(PK[] ids) {
        Assert.notEmpty(ids, "ids must not be empty");
        String hql = "from " + entityClass.getName() + " as model where model.id in(:ids)";
        return getHibernateTemplate().findByNamedParam(hql, "ids", ids);
    }

    @SuppressWarnings("unchecked")
    public T get(String propertyName, Object value) {
        Assert.hasText(propertyName, "propertyName must not be empty");
        Assert.notNull(value, "value is required");
        String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = ?";
        List list = getHibernateTemplate().find(hql, value);
        return (list == null || list.size() == 0) ? null : (T) list.get(0);
    }

    @SuppressWarnings("unchecked")
    public List<T> getList(String propertyName, Object value) {
        Assert.hasText(propertyName, "propertyName must not be empty");
        Assert.notNull(value, "value is required");
        String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = ?";
        return getHibernateTemplate().find(hql, value);
    }

    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        String hql = "from " + entityClass.getName();
        return getHibernateTemplate().find(hql);
    }

    public Long getTotalCount() {
        String hql = "select count(*) from " + entityClass.getName();
        List list = getHibernateTemplate().find(hql);
        return (list == null || list.size() == 0) ? 0 : (Long) list.get(0);
    }

    @Override
    public List<T> findByPager(Pager pager) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public List<T> findByPager(Pager pager, DetachedCriteria detachedCriteria) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public boolean isUnique(String propertyName, Object value) {
        Assert.hasText(propertyName, "propertyName must not be empty");
        Assert.notNull(value, "newValue is required");
        T object = get(propertyName, value);
        return object == null;
    }

    public boolean isExist(String propertyName, Object value) {
        Assert.hasText(propertyName, "propertyName must not be empty");
        Assert.notNull(value, "value is required");
        T object = get(propertyName, value);
        return (object != null);
    }

    @SuppressWarnings("unchecked")
    public PK save(T entity) {
        Assert.notNull(entity, "entity is required");
        return (PK) getHibernateTemplate().save(entity);
    }

    public void update(T entity) {
        Assert.notNull(entity, "entity is required");
        getHibernateTemplate().update(entity);
    }

    public void delete(T entity) {
        Assert.notNull(entity, "entity is required");
        getHibernateTemplate().delete(entity);
    }

    public void delete(PK id) {
        Assert.notNull(id, "id is required");
        T entity = load(id);
        getHibernateTemplate().delete(entity);
    }

    public void delete(PK[] ids) {
        Assert.notEmpty(ids, "ids must not be empty");
        for (PK id : ids) {
            T entity = load(id);
            getHibernateTemplate().delete(entity);
        }
    }

    /* TODO: remove them if no use */
    public void flush() {
        getSession().flush();
    }

    public void clear() {
        getSession().clear();
    }

    public void evict(Object object) {
        Assert.notNull(object, "object is required");
        getSession().evict(object);
    }
}